package fr.inserm.umr915.vcfannotator.annotators;

import java.util.regex.Pattern;

import fr.inserm.umr915.libjson.ArrayNode;
import fr.inserm.umr915.libjson.ObjectNode;
import fr.inserm.umr915.vcfannotator.AnnotationException;
import fr.inserm.umr915.vcfannotator.Variant;


import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.SecondaryCursor;

public class SiftAnnotator
	extends AbstractDelimitedAnnotator
	{
	private SecondaryCursor cursor=null;
	private DatabaseEntry key=new DatabaseEntry();
	private DatabaseEntry pKey=new DatabaseEntry();
	private DatabaseEntry data=new DatabaseEntry();
	private Variant.Binding variantBinding=new Variant.Binding();
	private String build=null;
	private int coordinateColumn=-1;
	private int codonColumn=-1;
	private int snpTypeColumn=-1;
	private int predictionColumn=-1;
	private int scoreColumn=-1;
	private int medianColumn=-1;
	private int subsitutionColumn=-1;
	private int regionColumn=-1;
	private ChromosomeNameConverter chromosomeNameConverter=new DefaultChromosomeNameConverter();
	
	
	public SiftAnnotator()
		{
		setPattern(Pattern.compile("[\t]"));
		}
	
	public String getBuild() {
		return build;
		}
	
	public void setBuild(String build)
		{
		this.build = build;
		}
	
	public ChromosomeNameConverter getChromosomeNameConverter()
		{
		return chromosomeNameConverter;
		}
	
	public void setChromosomeNameConverter(ChromosomeNameConverter chromosomeNameConverter)
		{
		this.chromosomeNameConverter = chromosomeNameConverter;
		}
	
	private static int indexOf(String tokens[],String key)
		{
		for(int i=0;i< tokens.length;++i)
			{	
			if(tokens[i].equals(key)) return i;
			}
		return -1;
		}
	
	private static boolean isBlank(String s)
		{
		return s==null || s.trim().length()==0;
		}
	
	@Override
	public void annotate(String[] tokens) throws AnnotationException
		{
		if(this.cursor==null)
			{
			this.cursor=super.baseDatabase.getVariantDatabase().openCursor(null, null);
			}
		for(int i=0;i< tokens.length;++i) tokens[i]=tokens[i].trim();
		if(getLineIndex()==1)
			{
			this.coordinateColumn= indexOf(tokens, "Coordinates");
			if(this.coordinateColumn==-1) throw new AnnotationException("header missing column 'Coordinates'");
			this.predictionColumn= indexOf(tokens, "Prediction");
			if(this.predictionColumn==-1) throw new AnnotationException("header missing column 'Prediction'");
			this.snpTypeColumn= indexOf(tokens, "SNP Type");
			if(this.snpTypeColumn==-1) throw new AnnotationException("header missing column 'SNP Type'");
			this.scoreColumn= indexOf(tokens, "Score");
			if(this.scoreColumn==-1) throw new AnnotationException("header missing column 'Score'");
			this.medianColumn= indexOf(tokens, "Median Info");
			if(this.medianColumn==-1) throw new AnnotationException("header missing column 'Median Info'");
			this.subsitutionColumn= indexOf(tokens, "Substitution");
			if(this.subsitutionColumn==-1) throw new AnnotationException("header missing column 'Substitution'");
			this.regionColumn= indexOf(tokens, "Region");
			if(this.regionColumn==-1) throw new AnnotationException("header missing column 'Region'");
			
			
			this.codonColumn= indexOf(tokens, "Codons");
			if(this.codonColumn==-1) throw new AnnotationException("header missing column 'Codons'");
			return;
			}
		
		if(tokens[this.snpTypeColumn].isEmpty()) return;
		if(tokens[this.snpTypeColumn].equals("NA")) return;
		
		
		ObjectNode meta=super.nodeFactory.createObjectNode();
		if(!isBlank(tokens[this.codonColumn])&& !tokens[this.codonColumn].equals("-")) meta.put("codon",tokens[this.codonColumn]);
	
		if(!isBlank(tokens[this.subsitutionColumn])&& !tokens[this.subsitutionColumn].equals("NA"))
			{
			meta.put("substitution",tokens[this.subsitutionColumn]);
			}
		
		meta.put("snp-type",tokens[this.snpTypeColumn]);
		
		
		
		
		String variant[]=tokens[this.coordinateColumn].split("[,]");

		
		if(tokens[this.predictionColumn].equals("DAMAGING"))
			{
			//ok
			}
		else if(tokens[this.predictionColumn].equals("DAMAGING *Warning! Low confidence."))
			{
			tokens[this.predictionColumn]="DAMAGING_LOW_CONFIDENCE";
			}
		else if(tokens[this.predictionColumn].equals("N/A"))
			{
			//ok
			}
		else if(tokens[this.predictionColumn].equals("Not scored"))
			{
			tokens[this.predictionColumn]="NOT_SCORED";
			}
		else if(tokens[this.predictionColumn].equals("TOLERATED"))
			{
			//ok
			}
		else
			{
			throw new AnnotationException("bad prediction:"+tokens[this.predictionColumn]);
			}
		meta.put("prediction", tokens[this.predictionColumn]);
		
		
		Variant var=new Variant(
			getBuild(),
			getChromosomeNameConverter().convertChromosome(variant[0]),
			Integer.parseInt(variant[1]),
			variant[3].substring(0,1).toUpperCase(),
			variant[3].substring(2).toUpperCase()
			);
		variantBinding.objectToEntry(var, key);
		
		OperationStatus op=cursor.getSearchKey(key,pKey, data, LockMode.DEFAULT);
		if(op!=OperationStatus.SUCCESS) return;
		
		
		
		ObjectNode annotation= nodeBinding.entryToObject(data).asObjectNode();
		ArrayNode array=(ArrayNode)annotation.get("sift");
		if(array==null)
			{
			array=super.nodeFactory.createArrayNode();
			annotation.put("sift",array);
			}

		if(!array.insert(meta)) return;
		
		LOG.info(array.toString()+" "+var);
		
		nodeBinding.objectToEntry(annotation, data);
		if(baseDatabase.getJsonDatabase().put(null, pKey, data)!=OperationStatus.SUCCESS)
			{
			throw new RuntimeException("Cannot re-insert "+var+":"+annotation);
			}
			
		}
	
	@Override
	public void cleanup() {
		if(this.cursor!=null)
			{
			this.cursor.close();
			}
		this.cursor=null;
		super.cleanup();
		}
	
	
	}
